<?php


namespace App\Services;


use Illuminate\Support\Facades\Cache;

class WechatAuth
{

    protected static $app_id = '';

    protected static $secret = '';

    public static function oauth2(string $code)
    {
        $access  = self::httpGet('https://api.weixin.qq.com/sns/oauth2/access_token?'.http_build_query([
                'appid' => self::$app_id,
                'secret'=> self::$secret,
                'code'  => $code,
                'grant_type' => 'authorization_code',
            ]));

        $access_token = json_decode($access,true);

        if (isset($access_token['errcode'])){
            throw new \Exception($access_token['errmsg'],$access_token['errcode']);
        }

        RedisTable::objectTableSave('app:wechat:'.$access_token['openid'],$access_token,$access_token['expires_in']);
        return $access_token;
    }

    public static function userInfo(string $openid)
    {
        $data = self::httpGet('https://api.weixin.qq.com/sns/userinfo?'.http_build_query([
                'access_token'  => collect(RedisTable::objectTable('app:wechat:'.$openid))['access_token'],
                'openid'        => $openid,
            ]));

        $userInfo = json_decode($data);

        if (isset($userInfo->errcode)){

            throw new \Exception($userInfo->errmsg,$userInfo->errcode);
        }

        return collect($userInfo)->all();
    }


    public static function authUrl(string $index, string $scope = 'snsapi_userinfo')
    {
        $url = config('app.url').'/wap/index.html';

        return 'https://open.weixin.qq.com/connect/oauth2/authorize?'.http_build_query([
                'appid' => self::$app_id,
                'redirect_uri'  => $index ? config('app.url').$index : $url,
                'response_type' => 'code',
                'scope'         => $scope,
                'state'         => 'STATE',
            ]).'#wechat_redirect';
    }

    public static function getSignPackage(string $pages = '')
    {

        $jsapiTicket = self::jsApiTicket();

        // 注意 URL 一定要动态获取，不能 hardcode.
        $url = config('app.url').($pages ? $pages : '/wap/index.html');

        $timestamp = time();
        $nonceStr = self::createNonceStr();

        // 这里参数的顺序要按照 key 值 ASCII 码升序排序
        $string = "jsapi_ticket=$jsapiTicket&noncestr=$nonceStr&timestamp=$timestamp&url=$url";

        $signature = sha1($string);

        return array(
            "appId"     => self::$app_id,
            "nonceStr"  => $nonceStr,
            "timestamp" => $timestamp,
            "url"       => $url,
            "signature" => $signature,
            "rawString" => $string
        );
    }

    public static function jsAccessToken()
    {
        if (! RedisTable::get('app:wechat:jssdk:access_token')){

            $res = self::httpGet('https://api.weixin.qq.com/cgi-bin/token?'.http_build_query([
                    'grant_type'    => 'client_credential',
                    'appid'         => self::$app_id,
                    'secret'        => self::$secret,
                ]));

            $data = json_decode($res);

            if (isset($data->errcode)){

                throw new \Exception($data->errmsg,$data->errcode);
            }

            RedisTable::save('app:wechat:jssdk:access_token',$data->access_token,$data->expires_in);

        }

        return RedisTable::get('app:wechat:jssdk:access_token');
    }

    public static function createNonceStr($length = 16)
    {
        $chars = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
        $str = "";
        for ($i = 0; $i < $length; $i++) {
            $str .= substr($chars, mt_rand(0, strlen($chars) - 1), 1);
        }
        return $str;
    }

    public static function jsApiTicket()
    {
        if (! RedisTable::get('app:wechat:jssdk:jsApiTicket')){

            $res = self::httpGet('https://api.weixin.qq.com/cgi-bin/ticket/getticket?'.http_build_query([
                    'type'          => 'jsapi',
                    'access_token'  => self::jsAccessToken(),
                ]));

            $data = json_decode($res);

            if ($data->errcode > 0){

                throw new \Exception($data->errmsg,$data->errcode);
            }

            RedisTable::save('app:wechat:jssdk:jsApiTicket',$data->ticket,$data->expires_in);

        }

        return RedisTable::get('app:wechat:jssdk:jsApiTicket');
    }

    public static function httpGet($url) {
        $curl = curl_init();
        curl_setopt($curl, CURLOPT_RETURNTRANSFER, true);
        curl_setopt($curl, CURLOPT_TIMEOUT, 500);
        // 为保证第三方服务器与微信服务器之间数据传输的安全性，所有微信接口采用https方式调用，必须使用下面2行代码打开ssl安全校验。
        // 如果在部署过程中代码在此处验证失败，请到 http://curl.haxx.se/ca/cacert.pem 下载新的证书判别文件。
        curl_setopt($curl, CURLOPT_SSL_VERIFYPEER, false);
        curl_setopt($curl, CURLOPT_SSL_VERIFYHOST, 2);
        curl_setopt($curl, CURLOPT_URL, $url);

        $res = curl_exec($curl);
        curl_close($curl);

        return $res;
    }
}
